Ext.Loader.setConfig({enabled: true});
Ext.Loader.setPath('Ext.ux', 'ext-ux');
Ext.require([
    'Ext.ux.grid.FiltersFeature',
    'Ext.grid.*',
    'Ext.data.*',
    'Ext.toolbar.Paging',
    'Ext.form.*',
    'Ext.panel'
]);

Ext.onReady(function() {

    var tabTimeCreatedCache = {};
    var GridItemsPerPage    = 50;

    Ext.QuickTips.init();

    var filters = {
        ftype  : 'filters',
        encode : true
    };

    function storeIsLoaded(myId, columns) {
        var maxDataLength = {};

        var columns = Ext.getCmp('grid.panel.' + myId).columns;
        var records = Ext.getCmp('grid.panel.' + myId).getStore().data.items;

        for (var i = 0; i < records.length; i++) {
            var record = records[i].data;

            for (var k = 0; k < columns.length; k++) {
                var colName = columns[k].dataIndex;

                var dataLength = 0;

                if (record[colName] != null) {
                    dataLength = record[colName].length;
                }

                if (maxDataLength[colName] == null) {
                    maxDataLength[colName] = dataLength;
                }
                else if (dataLength > maxDataLength[colName]) {
                    maxDataLength[colName] = dataLength;
                }
            }
        }

        if (records.length > 0) {
            for (var ii = 0; ii < columns.length; ii++) {
                columns[ii].width = Math.round((columns[ii].dataIndex.length + maxDataLength[columns[ii].dataIndex]) * 6.5);
            }
            Ext.getCmp('grid.panel.' + myId).getView().refresh();
        }
        else {
            for (var ii = 0; ii < columns.length; ii++) {
                columns[ii].width = Math.round(columns[ii].dataIndex.length * 6.5);
            }
            Ext.getCmp('grid.panel.' + myId).getView().refresh();
        }
    }

    function setColWidth(myId) {
        var maxDataLength = {};

        var store        = Ext.getCmp('grid.panel.' + myId).getStore();
        var theStore     = [store];
        var len          = theStore.length;
        var loadedStores = 0;

        function check() {
            if (++loadedStores === len) {
                storeIsLoaded(myId);
            }
        }

        if (store.isLoading() == false) {
            storeIsLoaded(myId);
        }

        for (var i = 0; i < len; ++i) {
            theStore[i].on('load', check, null, {single: true});
        }
    }

    function createFormatStore(obj, col, results) {
        var formatComboMenu = Ext.getCmp('formatComboMenu.' + results.id);
        if (formatComboMenu) {
            if (col.type == 'integer') {
                var formatStore = Ext.create('Ext.data.ArrayStore', {
                    fields : ['id'],
                    data   : [['default'],['0,000']]
                });
                formatComboMenu.bindStore(formatStore);
            }
            else if (col.type == 'float') {
                var formatStore = Ext.create('Ext.data.ArrayStore', {
                    fields : ['id'],
                    data   : [['default'],['0,000.00'],['0,000.0000'],
                        ['0.00'],['0.0000'],['0.000000'],['0.000.000000']]
                });
                formatComboMenu.bindStore(formatStore);
            }
            else if (col.type == 'string') {
                var formatStore = Ext.create('Ext.data.ArrayStore', {
                    fields : ['id'],
                    data   : [['default'],['uppercase'],['lowercase']]
                });
                formatComboMenu.bindStore(formatStore);
            }
            else if (col.type == 'datetime') {
                var formatStore = Ext.create('Ext.data.ArrayStore', {
                    fields : ['id'],
                    data   : [['default'],['TBD datetime']]
                });
                formatComboMenu.bindStore(formatStore);
            }
            else if (col.type == 'date') {
                var formatStore = Ext.create('Ext.data.ArrayStore', {
                    fields : ['id'],
                    data   : [['default'],['TBD date']]
                });
                formatComboMenu.bindStore(formatStore);
            }
        }
    }

    function getTableDefCols (jsonObj, results) {
         var columnArray    = [];
         var doAutoColWidth = 1;

         for (var i = 0; i < jsonObj['columns'].length; i++) {
             var colName = jsonObj.columns[i];
             var colObj;
             if (jsonObj['column'][colName]) {
                 //var column_label  = jsonObj['column'][colName].column_label;
                 var displayWidth  = jsonObj['column'][colName].display_width;
                 var displayHidden = jsonObj['column'][colName].hidden;
                 var widthSize     = colName.length + 150;
                 var filterVal     = jsonObj['column'][colName].filter;
                 var sortVal       = jsonObj['column'][colName].sort;
                 var label         = jsonObj['column'][colName].column_label;
                 var columnType    = jsonObj['column'][colName].column_type;

                 if (displayWidth == null) {
                     displayWidth = widthSize;
                 }
                 else {
                     doAutoColWidth = 0;
                 }

                 if (displayHidden == null) {
                     displayHidden = false;
                 }

                 var columnLabel = label;
                 if (!columnLabel) {
                     columnLabel = colName;
                 }

                 colObj = {header : columnLabel, sortable : true, dataIndex : colName,
                     width : displayWidth, filterable : true, hidden : displayHidden, type : columnType,
                     listeners: {headertriggerclick: function(obj, col) {createFormatStore(obj, col, results);}}
                 };

                 if (filterVal) {
                     colObj.filter = {value: filterVal, active: true};
                 }

                 if (sortVal && results.sorters == null) {
                     colObj.sort     = sortVal;
                     results.sorters = {property: colName, direction : sortVal};
                 }
             }
             else {
                 // TODO: Figure out why the server EVER returns columns which are not in the jsonObj['column'] hash.
                 //       This is the safety-net work-around.
                 colObj = {header : colName, sortable : true, dataIndex : colName, filterable : true};
             }

             columnArray.push(colObj);
         }

         if (results != null) {
             results.doAutoColWidth = doAutoColWidth;
         }

         return (columnArray);
    }

    function getTableDefColsSql (jsonObj, results) {
         var columnArray    = [];
         var doAutoColWidth = 1;

         for (var i = 0; i < jsonObj['columns'].length; i++) {
             var colName = jsonObj.columns[i];
             var colObj;
             if (jsonObj['column'][colName]) {
                 //var column_label  = jsonObj['column'][colName].column_label;
                 var displayWidth  = jsonObj['column'][colName].display_width;
                 var displayHidden = jsonObj['column'][colName].hidden;
                 var widthSize     = colName.length + 150;
                 var label         = jsonObj['column'][colName].column_label;
                 var columnType    = jsonObj['column'][colName].column_type;

                 if (displayWidth == null) {
                     displayWidth = widthSize;
                 }
                 else {
                     doAutoColWidth = 0;
                 }

                 if (displayHidden == null) {
                     displayHidden = false;
                 }

                 var columnLabel = label;
                 if (!columnLabel) {
                     columnLabel = colName;
                 }

                 colObj = {header : columnLabel, sortable : false, dataIndex : colName,
                     width : displayWidth, hidden : displayHidden, type : columnType};
             }
             else {
                 // TODO: Figure out why the server EVER returns columns which are not in the jsonObj['column'] hash.
                 //       This is the safety-net work-around.
                 colObj = {header : colName, dataIndex : colName, sortable : false};
             }

             columnArray.push(colObj);
         }

         if (results != null) {
             results.doAutoColWidth = doAutoColWidth;
         }

         return (columnArray);
    }

    function getTableDefRels (jsonObj, relationship, relationships) {
        var rel = jsonObj['relationship'];

        if (rel) {
            for(var key in rel) {
                relationship[key] = rel[key];
            }

            for (var i = 0; i < jsonObj['relationships'].length; i++) {
                relationships.push(jsonObj.relationships[i]);
            }
        }
    }

    function getTableDataStore (jsonObj, tabId, dbName, schema, results, aggChecked) {
        var tableDataStore = Ext.create('Ext.data.JsonStore',{
            autoLoad   : true,
            storeId    : 'table.data.store.' + tabId,
            pageSize   : GridItemsPerPage,
            remoteSort : true,
            proxy      : Ext.create('Ext.data.HttpProxy',{
                timeout: 90000, // 90 seconds
                type        : 'ajax',
                extraParams : {database : dbName, schema : schema, table : jsonObj.table_name,
                    columns : jsonObj.columns.join(","), rowtype : 'object', aggregate : aggChecked},
                url         : 'extjs-grid.php',
                reader : {
                    type          : 'json',
                    root          : 'data',
                    totalProperty : 'total'
                }
            }),
            fields     : jsonObj.columns,
            sortOnLoad : true,
            sorters    : results.sorters
        });

        return(tableDataStore);
    }

    function getTableDataStoreSql (jsonObj, tabId, dbName, schema, results) {
        var tableDataStore = Ext.create('Ext.data.JsonStore',{
            autoLoad   : true,
            storeId    : 'table.data.store.' + tabId,
            pageSize   : GridItemsPerPage,
            remoteSort : true,
            proxy      : Ext.create('Ext.data.HttpProxy',{
                timeout: 90000, // 90 seconds
                type        : 'ajax',
                extraParams : {sql : jsonObj.sql, database : dbName, schema : schema, rowtype : 'object'},
                url         : 'extjs-grid.php',
                reader : {
                    type          : 'json',
                    root          : 'data',
                    totalProperty : 'total'
                }
            }),
            fields     : jsonObj.columns
            //sortOnLoad : true,
            //sorters    : results.sorters
        });

        return(tableDataStore);
    }


    function createGridSaveButton (tabId) {
        var gridSaveButton = Ext.create('Ext.Action', {
            id      : 'gridtoolbar.save.' +  tabId,
            tooltip : {text : 'Save the state of the grid, i.e. column width'},
            icon    : 'images/save.gif',
            text    : 'Save',
            handler : function(widget, event) {
                var colObj     = [];
                var encodedObj = {};
                var columns    = Ext.getCmp('grid.panel.' + tabId).columns;
                var filters    = Ext.getCmp('grid.panel.' + tabId).filters.getFilterData();

                var filterObj = {};
                for (var i = 0; i < filters.length; i++) {
                    filterObj[filters[i].field] = {type : filters[i].data.type, value : filters[i].data.value};
                }

                for (var i = 0; i < columns.length; i++) {
                    var sortState = columns[i].sortState;
                    var stateId   = columns[i].stateId;
                    var colName   = columns[i].dataIndex;
                    var colText   = columns[i].text;
                    var hidden    = columns[i].hidden;
                    var width     = columns[i].width;
                    var colDef    = {"id" : stateId, "width" : width, "name" : colName, "column_label" : colText};

                    if (sortState) {
                        colDef.sort = sortState;
                    }
                    if (hidden) {
                        colDef.hidden = hidden;
                    }
                    if (filterObj[colName] != null) {
                        colDef.filter     = filterObj[colName].value;
                        colDef.filtertype = filterObj[colName].type;
                    }

                    colObj.push(colDef);
                }

                encodedObj.columns = colObj;
                if (Ext.getCmp('aggregate.checkbox.' + tabId).getValue()) {
                    encodedObj.aggregate = true;
                }
                encodedObj = Ext.encode(encodedObj);

                Ext.Ajax.request({
                    url       : 'extjs-store.php',
                    params    : {type : 'grid', op : 'put', key : tabId, data : encodedObj},
                    autoAbort : false,
                    success : function(response){
                        Ext.MessageBox.show({
                           title   : 'Status',
                           msg     : 'Changes saved successfully.',
                           buttons : Ext.MessageBox.OK
                        });
                    },
                    failure: function(response, opts) {
                        Ext.MessageBox.show({
                           title   : 'Status',
                           msg     : 'server-side failure with status code ' + response.status,
                           buttons : Ext.MessageBox.OK
                        });
                    }
                });
            }
        });

        return(gridSaveButton);
    }

    function createGridTaskButton (tabId, labelNm) {
        var gridTaskButton = Ext.create('Ext.Action', {
            id      : 'gridtoolbar.task.' + tabId,
            tooltip : {text : 'Add the view to the Tasks tree'},
            icon    : 'images/add.png',
            text    : 'Add to Tasks',
            handler : function(widget, event) {
                Ext.Ajax.request({
                    url       : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/apptree',
                    params    : {type : 'screens', op : 'new', parent_id : 'src', label : labelNm, action: tabId},
                    autoAbort : false,
                    success : function(response){
                        var jsonObj = Ext.JSON.decode (response.responseText);
                        var treeNodeId = jsonObj.tree_id;
                        var root = Ext.getCmp('screen.tree.panel').getRootNode();

                        root.appendChild({
                            id :  treeNodeId,
                            text: labelNm,
                            action: tabId,
                            leaf: true
                        });
                    },
                    failure: function(response, opts) {
                        Ext.MessageBox.show({
                           title   : 'Status',
                           msg     : 'server-side failure with status code ' + response.status,
                           buttons : Ext.MessageBox.OK
                        });
                    }
                });
            }
        });

        return(gridTaskButton);
    }

    function createGridSqlButton (tabId) {
        var gridSqlButton = Ext.create('Ext.Action', {
            id      : 'gridtoolbar.sql.' + tabId,
            tooltip : {text : 'Show Sql'},
            icon    : 'images/preview.png',
            text    : 'Show Sql',
            handler : function(widget, event) {

                var store = Ext.getCmp('grid.panel.' + tabId).getStore();
                var sql   = store.proxy.reader.rawData.sql;

                Ext.create('Ext.window.Window', {
                    id           : 'window.sql.' + tabId,
                    width        : 550,
                    maxHeight    : 550,
                    shadowOffset : 25,
                    y            : 50,
                    title        : 'Sql',
                    layout       : 'fit',
                    tools  : [{
                        type    : 'save',
                        handler : function(){
                            var arrayId = tabId.split('.');

                            if (arrayId.length >= 4) {

                                var sql        = Ext.getCmp('textareafield.sql.' + tabId).getValue();
                                var colObj     = [];
                                var encodedObj = {};
                                var columns    = Ext.getCmp('grid.panel.' + tabId).columns;

                                for (var i = 0; i < columns.length; i++) {
                                    var stateId   = columns[i].stateId;
                                    var colName   = columns[i].dataIndex;
                                    var colText   = columns[i].text;
                                    var hidden    = columns[i].hidden;
                                    var width     = columns[i].width;
                                    var colDef    = {"id" : stateId, "width" : width, "name" : colName, "column_label" : colText};

                                    if (hidden) {
                                        colDef.hidden = hidden;
                                    }

                                    colObj.push(colDef);
                                }

                                encodedObj.columns = colObj;
                                encodedObj.sql     = sql;

                                encodedObj = Ext.encode(encodedObj);

                                Ext.Ajax.request({
                                    url       : 'extjs-store.php',
                                    params    : {type : 'grid', op : 'put', key : tabId, data : encodedObj},
                                    autoAbort : false,
                                    success   : function(response){
                                        var jsonObj = Ext.JSON.decode(response.responseText);
                                        if (jsonObj.success == false) {
                                            Ext.MessageBox.show({
                                                title   : 'Status',
                                                msg     : jsonObj.msg,
                                                buttons : Ext.MessageBox.OK
                                            });
                                        }
                                        else {
                                            var arrayId   = tabId.split('.');
                                            var dbName    = arrayId[0];
                                            var schema    = arrayId[1];
                                            var tableName = arrayId[2];

                                            Ext.Ajax.request({
                                                url       : 'extjs-table-def.php',
                                                params    : {database : dbName, schema : schema, table : tableName, view : tabId},
                                                autoAbort : false,
                                                success : function(response){
                                                    var jsonObj        = Ext.JSON.decode (response.responseText);
                                                    var results        = {};
                                                    var columnArray    = getTableDefColsSql (jsonObj, results);
                                                    var tableDataStore = getTableDataStoreSql (jsonObj, tabId, dbName, schema, results);
                                                    var gridView       = Ext.getCmp('grid.panel.' + tabId);

                                                    var dockedItems = gridView.getDockedComponent(Ext.getCmp('toolbar.grid.panel.' + tabId)).items.items;
                                                    var itemsToRemove = [];
                                                    for (var i = 0; i < dockedItems.length; i++) {
                                                        if (dockedItems[i].id == 'aggregate.checkbox.' + tabId || dockedItems[i].id == 'relationship.combo.' + tabId) {
                                                            itemsToRemove.push(dockedItems[i].id);
                                                        }
                                                    }
                                                    for (var i = 0; i < itemsToRemove.length; i++) {
                                                         gridView.getDockedComponent(Ext.getCmp('toolbar.grid.panel.' + tabId)).remove(itemsToRemove[i]);
                                                    }

                                                    gridView.reconfigure(tableDataStore, columnArray);

                                                    var gridFormatComboMenu = createFormatComboMenu (tabId);
                                                    var gridCustomLabelMenu = createCustomLabelMenu (tabId);
                                                    var menu = gridView.headerCt.getMenu();
                                                    menu.add([
                                                        {
                                                            icon : 'images/columns.gif',
                                                            text : 'Column Label',
                                                            menu : [gridCustomLabelMenu]
                                                        },
                                                        {
                                                            icon : 'images/columns.gif',
                                                            text : 'Format Data',
                                                            menu : [gridFormatComboMenu]
                                                        }
                                                    ]);

                                                    Ext.getCmp('paging.toolbar.'  + tabId).bindStore(tableDataStore);

                                                    setColWidth(tabId);

                                                    Ext.getCmp('window.sql.' + tabId).close();
                                                }
                                            });
                                        }
                                    }
                                });
                            }
                            else {
                                Ext.MessageBox.show({
                                    title   : 'Status',
                                    msg     : 'You can only save Sql in a copied view.',
                                    buttons : Ext.MessageBox.OK
                                });
                            }
                        }
                    }],
                    items: [{
                        xtype : 'textareafield',
                        id    : 'textareafield.sql.' + tabId,
                        grow  : true,
                        value : sql,
                        fieldStyle: {
                            'fontSize' : '11px'
                        }
                    }]
                }).show();
            }
        });

        return(gridSqlButton);
    }

    function createFormatComboMenu (tabId, results) {
        var gridFormatComboMenu = new Ext.form.ComboBox({
            id           : 'formatComboMenu.' + tabId,
            width        : 140,
            displayField : 'id',
            valueField   : 'id',
            store : new Ext.data.ArrayStore({
                fields : ['id'],
                data   : []
            }),
            listeners : {
                select : function (obj, records, eOpts ) {
                    var grid = Ext.getCmp('grid.panel.' + tabId);
                    var columnDataIndex = grid.headerCt.getMenu().activeHeader.dataIndex;
                    var gridColumns = grid.headerCt.getGridColumns();

                    var columnArray = [];
                    var colObj;

                    for (var i = 0; i < gridColumns.length; i++) {
                        var headerVal     = gridColumns[i].text;
                        var sortableVal   = gridColumns[i].sortable;
                        var dataIndexVal  = gridColumns[i].dataIndex;
                        var widthVal      = gridColumns[i].width;
                        var filterableVal = gridColumns[i].filterable;
                        var hiddenVal     = gridColumns[i].hidden;
                        var typeVal       = gridColumns[i].type; //integer,string,float,datetime
                        var xtypeVal      = gridColumns[i].xtype;
                        var formatVal     = gridColumns[i].format;
                        var rendererVal   = gridColumns[i].renderer;

                        colObj = {header : headerVal, sortable : sortableVal, dataIndex : dataIndexVal,
                            width : widthVal, filterable : filterableVal, hidden : hiddenVal, type : typeVal,
                            listeners: {headertriggerclick: function(obj, col) {createFormatStore(obj, col, results);}}
                        };

                        if (formatVal) {
                            colObj.xtype  = xtypeVal;
                            colObj.format = formatVal;
                        }
                        else if (rendererVal && typeVal == 'string') {
                            colObj.renderer = rendererVal;
                        }

                        if (gridColumns[i].dataIndex == columnDataIndex) {
                            if (this.getValue() == 'default') {
                                colObj.xtype    = '';
                                colObj.format   = '';
                                colObj.renderer = '';
                            }
                            else {
                                if (typeVal == 'integer' || typeVal == 'float') {
                                    colObj.xtype  = 'numbercolumn';
                                    colObj.format = this.getValue();
                                }
                                else if (typeVal == 'string') {
                                    if (this.getValue() == 'uppercase') {
                                        colObj.renderer = Ext.util.Format.uppercase;
                                    }
                                    else if (this.getValue() == 'lowercase') {
                                        colObj.renderer = Ext.util.Format.lowercase;
                                    }
                                }
                            }
                        }
                        columnArray.push(colObj);
                    }

                    var store = Ext.getCmp('grid.panel.' + tabId).getStore();
                    grid.reconfigure(store, columnArray);

                    var gridFormatComboMenu = createFormatComboMenu (tabId, results);
                    var gridCustomLabelMenu = createCustomLabelMenu (tabId);
                    var menu = grid.headerCt.getMenu();
                    menu.add([
                        {
                            icon : 'images/columns.gif',
                            text : 'Column Label',
                            menu : [gridCustomLabelMenu]
                        },
                        {
                            icon : 'images/columns.gif',
                            text : 'Format Data',
                            menu : [gridFormatComboMenu]
                        }
                    ]);
                }
            }
        });

        return(gridFormatComboMenu);
    }

    function createCustomLabelMenu (tabId) {
        var gridCustomLabelMenu = Ext.create('Ext.form.field.Text', {
            id : 'customLabelMenu.' + tabId,
            enableKeyEvents : true,
            listeners : {
                keypress: function (obj, e) {
                    if (e.keyCode == e.ENTER) {
                        var grid            = Ext.getCmp('grid.panel.' + tabId);
                        var columnText      = grid.headerCt.getMenu().activeHeader.text;
                        var columnDataIndex = grid.headerCt.getMenu().activeHeader.dataIndex;

                        var gridColumns = grid.headerCt.getGridColumns();

                        for (var i = 0; i < gridColumns.length; i++) {
                            if (gridColumns[i].dataIndex == columnDataIndex) {
                                grid.columns[i].setText(this.getValue());
                            }
                        }
                    }
                }
            }
        });
        return(gridCustomLabelMenu);
    }

    function createGridSaveAsButton (tabId) {
        var gridSaveAsButton = Ext.create('Ext.Action', {
            id      : 'gridtoolbar.saveas.' + tabId,
            tooltip : {text : 'Copy the view to the Tables tree'},
            icon    : 'images/disk.png',
            text    : 'Save As Copy',
            handler : function(widget, event) {
                Ext.MessageBox.prompt('Copy As', 'Please enter name:', function(btn, folderVal){
                    if (btn == 'ok'){
                        var textVal    = folderVal;
                        var colObj     = [];
                        var encodedObj = {};
                        var columns    = Ext.getCmp('grid.panel.' + tabId).columns;
                        var filters    = Ext.getCmp('grid.panel.' + tabId).filters.getFilterData();

                        var filterObj = {};
                        for (var i = 0; i < filters.length; i++) {
                            filterObj[filters[i].field] = {type : filters[i].data.type, value : filters[i].data.value};
                        }

                        for (var i = 0; i < columns.length; i++) {
                            var sortState = columns[i].sortState;
                            var stateId   = columns[i].stateId;
                            var colName   = columns[i].dataIndex;
                            var colText   = columns[i].text;
                            var hidden    = columns[i].hidden;
                            var width     = columns[i].width;
                            var colDef    = {"id" : stateId, "width" : width, "name" : colName, "column_label" : colText};

                            if (sortState) {
                                colDef.sort = sortState;
                            }
                            if (hidden) {
                                colDef.hidden = hidden;
                            }
                            if (filterObj[colName] != null) {
                                colDef.filter     = filterObj[colName].value;
                                colDef.filtertype = filterObj[colName].type;
                            }

                            colObj.push(colDef);
                        }

                        encodedObj.columns = colObj;

                        if (Ext.getCmp('aggregate.checkbox.' + tabId).getValue()) {
                             encodedObj.aggregate = true;
                        }
                        encodedObj = Ext.encode(encodedObj);

                        Ext.Ajax.request({
                            url       : 'extjs-store.php',
                            params    : {type : 'grid', op : 'put', key : tabId, data : encodedObj, label : textVal},
                            autoAbort : false,
                            success : function(response){
                                var jsonObj = Ext.JSON.decode (response.responseText);
                                var selectedNode = Ext.getCmp('table.tree.panel').getSelectionModel().getSelection()[0];

                                if (selectedNode.data.leaf) {
                                    var arrayId   = tabId.split('.');
                                    var dbName    = arrayId[0];
                                    var schema    = arrayId[1];
                                    var tableName = arrayId[2];

                                    var modText      = textVal.replace(/\s+/g,"_");
                                    var modTextLower = modText.toLowerCase();

                                    var nodeId = dbName +'.'+ schema +'.'+ tableName +'.'+ modTextLower;

                                    selectedNode.parentNode.insertBefore({
                                        id     : nodeId,
                                        text   : textVal,
                                        leaf   : true
                                    }, selectedNode);
                                }
                                else {
                                    var store        = Ext.getCmp('table.tree.panel').getStore();
                                    var modText      = textVal.replace(/\s+/g,"_");
                                    var modTextLower = modText.toLowerCase();
                                    var nodeId       = tabId + '.' +  modTextLower;

                                    selectedNode.expand();

                                    if (selectedNode.store.treeStore.tree.nodeHash[nodeId] == null && store.isLoading() == false) {
                                        selectedNode.appendChild({
                                            id     : nodeId,
                                            text   : textVal,
                                            action : null,
                                            leaf   : true
                                        });
                                    }
                                }
                            },
                            failure: function(response, opts) {
                                Ext.MessageBox.show({
                                   title   : 'Status',
                                   msg     : 'server-side failure with status code ' + response.status,
                                   buttons : Ext.MessageBox.OK
                                });
                            }
                        });
                    }
                });
            }
        });

        return(gridSaveAsButton);
    }

    function createExportMenu (tabId) {
        var exportMenu = Ext.create('Ext.menu.Menu', {
            id     : 'export.menu.' + tabId,
            style  : {
                overflow : 'visible'
            },
            items  : [
                {
                    text    : 'To File',
                    tooltip : {text : 'Export this tab\'s data to a file'},
                    handler : function(widget, event) {
                        msg = "File Name: <input type=\"text\" id=\"fname\">" +
                              "<select id=\"format\"><option value='CSV'>.csv</option><option value='XLS'>.xls (todo)</option></select>" +
                              "<br><br>" +
                              "Save To : <select id=\"to\"><option value='.'>/ (Root Directory)</option>";

                        var nodes = documentTreeStore.tree.nodeHash;

                        for (var key in nodes) {
                            // skip non dirs and root dir
                            if ( (nodes[key].raw.leaf != undefined && nodes[key].raw.leaf == true) || key == "src")
                                continue;
                            else if ( /'/.test(key) )
                                key = key.replace(/'/,"\\\'");

                            msg += "<option value='" + key + "'>" + key + "</option>";
                        }

                        msg += "</select><br>" +
                               "Data Range: <select id=\"scope\"><option value='CURRENT_PAGE'>Current Page Only</option><option value='ALL_PAGES'>All Pages</option></select>" +
                               "<br><br>" +
                               "<input type=\"checkbox\" id=\"overwrite\"> Overwrite existing files with same name?";

                        Ext.MessageBox.show({
                                title   : "Export Data",
                                width   : 300,
                                msg     : msg,
                                buttons : Ext.MessageBox.OKCANCEL,
                                fn: function(btn) {
                                    if( btn == 'ok') {

                                        var gridViewCols = Ext.getCmp('grid.panel.' + tabId).columns;
                                        var arrayId      = tabId.split('.');
                                        var dbName       = arrayId[0];
                                        var schema       = arrayId[1];
                                        var tableName    = arrayId[2];
                                        var aggChecked   = Ext.getCmp('aggregate.checkbox.' + tabId).checked;
                                        var columns      = new Array();
                                        var fname        = Ext.get('fname').getValue();
                                        var format       = Ext.get('format').getValue();
                                        var scope        = Ext.get('scope').getValue();
                                        var to           = Ext.get('to').getValue();
                                        var overwrite    = (document.getElementById('overwrite').checked == true) ? 1 : 0;

                                        gridViewCols.forEach( function(element, index, array){ columns.push(element.dataIndex) });

                                        Ext.Ajax.request({
                                            url       : 'extjs-grid.php',
                                            params    : { database : dbName, schema : schema, table : tableName,
                                                          columns : columns.join(","), rowtype : 'object', aggregate : aggChecked,
                                                          format : format, fname : fname, overwrite : overwrite, to : to},
                                            autoAbort : false,
                                            success : function(response) {
                                                if (Ext.decode(response.responseText).success == true){
                                                    storeExpandedDocumentTreeNodes();
                                                    documentTreeStore.reload();
                                                }
                                                else {
                                                    alert(Ext.decode(response.responseText).msg);
                                                }
                                            },
                                            failure: function(response, opts) {
                                                Ext.MessageBox.show({
                                                   title   : 'Status',
                                                   msg     : 'server-side failure with status code ' + response.status,
                                                   buttons : Ext.MessageBox.OK
                                                });
                                            }
                                        });
                                    }
                                }
                            });
                    }
                },
                {
                    text    : 'Selected Rows To Clipboard',
                    tooltip : {text : 'Copies highlighted rows to clipboard as a comma-delimited string'},
                    handler : function(widget, event) {

                        var selectedNodes = Ext.getCmp('grid.panel.' + tabId).getSelectionModel().getSelection();

                        if (selectedNodes == null || selectedNodes.length <= 0){
                            Ext.MessageBox.show({
                                msg   : "No rows selected. Please select the rows you wish to export to your clipboard",
                                icon  : Ext.MessageBox.WARNING,
                                title : "Error!",
                                width : 175,
                            });
                        }
                        else {

                            var msg = "<input type=\"checkbox\" id=\"include_headers\" checked> Include Column Headers?" +
                                  "<br><br>" +
                                  "Select Delimiter Type:<br>" +
                                  "<select id=\"type\"><option value=\"CSV\">CSV-Style (quote fields containing delimiter)</option><option value=\"PIPE\">Pipe-Style (escape delimiters in data)</option></select>" +
                                  "<br><br>" +
                                  "Delimiter : <input id=\"delimiter\" name=\"delimiter\" type=\"text\" value=\",\" size=\"5\" \>" +
                                  "<br><br>" +
                                  "<input type=\"checkbox\" id=\"useNullKeyword\"> Use null Keyword?";

                            Ext.MessageBox.wait({
                                title   : "Export Data to Clipboard",
                                width   : 300,
                                msg     : msg,
                                buttons : Ext.MessageBox.OKCANCEL,
                                fn: function(btn) {
                                        if( btn == 'ok') {
                                            var delimitedString = "";
                                            var columns         = new Array();
                                            var delimiter       = Ext.get('delimiter').getValue();
                                            var includeHeaders  = (document.getElementById("include_headers").checked == true) ? 1 : 0;
                                            //var styleIndex      = document.getElementById('type').selectedIndex;
                                            //var style           = document.getElementById('type').item(styleIndex).value;
                                            var style           = Ext.get('type').getValue();
                                            var useNullKeyword  = (document.getElementById('useNullKeyword').checked == true) ? 1 : 0;
                                            var re              = new RegExp("(" + delimiter + ")", "g");

                                            ///////////////
                                            // headers
                                            ///////////////
                                                for (var col in selectedNodes[0].data){
                                                    columns.push(col);

                                                    if (!includeHeaders)
                                                        continue;

                                                    if ( col == undefined && !useNullKeyword )
                                                        delimitedString += delimiter;
                                                    else if(re.test(col)){
                                                        if (style == 'CSV')
                                                            delimitedString += '"' + col + '"' + delimiter;
                                                        else
                                                            delimitedString += value.replace( re , "\\$1") + delimiter;
                                                    }
                                                    else
                                                        delimitedString += col + delimiter;
                                                }
                                                delimitedString = delimitedString.substr(0, delimitedString.length - delimiter.length);
                                                delimitedString += "\n";

                                            ////////////////
                                            // values
                                            ////////////////

                                            selectedNodes.forEach( function(node){//, index, array){
                                                for (var colIdx in columns){
                                                    value = node.data[ columns[colIdx] ];

                                                    if ( value == undefined && !useNullKeyword )
                                                        delimitedString += delimiter;
                                                    else if ( re.test(value) ){
                                                        if (style == 'CSV')
                                                            delimitedString += '"' + value + '"' + delimiter;
                                                        else
                                                            delimitedString += value.replace( re , "\\$1") + delimiter;

                                                    }
                                                    else
                                                        delimitedString += value + delimiter;
                                                }

                                                delimitedString = delimitedString.substr(0, delimitedString.length - delimiter.length);
                                                delimitedString += "\n";
                                            });

                                            var textDisplayWindow = Ext.create('Ext.window.Window', {
                                                title    : 'Please copy this text to your clipboard:',
                                                height   : 200,
                                                width    : 350,
                                                closable : false,
                                                layout   : 'fit',
                                                buttons  : [
                                                    {
                                                        text    : 'Done' ,
                                                        handler : function() { Ext.WindowManager.getActive().close(); },
                                                    },
                                                ],
                                            });

                                            var textArea = Ext.create('Ext.Component', {
                                                html   : "<textarea readonly=\"readonly\" style=\"resize:none; width:100%; height:100%;\" id=\"csvTextArea\" border=\"0\" >" + delimitedString + "</textarea>",
                                                width  : 300,
                                                height : 200,
                                            });

                                            textDisplayWindow.items.add(textArea);
                                            textDisplayWindow.show();
                                            document.getElementById('csvTextArea').focus();
                                            document.getElementById('csvTextArea').select();
                                        }
                                        else {
                                            return;
                                        }
                                    }
                            });


                           /*
                            console.log("done with form...");

                             var msg2 = "Copy this text to your clipboard: <br><br><textarea readonly=\"readonly\" cols=\"50\" rows=\"5\" name=\"clipboard_text\" id=\"clipboard_text\" style=\"resize:none\">" + delimitedString + "</textarea>";

                                            Ext.MessageBox.show({
                                                title         : "Copy Text",
                                                msg           : msg2,
                                                buttons       : Ext.MessageBox.OK,
                                                animateTarget : this,
                                                autoRender    : true,
                                                closeable     : false,
                                                //fn: function(btn) {
                                                //    if( btn == 'ok') { }
                                                //},
                                            });
                                            */

                        }
                    }
                }
                //{ // TODO: implement this for remote installations of dbFront
                //    text    : 'Publish To dbfoundry (todo)',
                //    tooltip : {text : 'send data to dbfoundry from a locally installed copy of dbfront'},
                //    handler : function(widget, event) {
                //    },
                //    visible : false,
                //}

               ],
           })

           return (exportMenu);
       }

    function generateAlert (title, msg) {
        var msgCt = Ext.core.DomHelper.insertFirst(document.body, {id:'msg-div'}, true);
        var m = Ext.core.DomHelper.append(msgCt, '<div class="msg"><h3>' + title + '</h3><p>' + msg + '</p></div>', true);
        m.hide();
        m.slideIn('t').ghost("t", { delay: 2000, remove: true});
    }

    function createExportMenuButton (exportMenu) {
        var exportMenuButton = Ext.create('Ext.Action', {
            text : 'Export Data',
            menu : exportMenu
        });

        return(exportMenuButton);
    }

    function createGridMenu (tabId) {
        var gridMenu = Ext.create('Ext.menu.Menu', {
            id    : 'gridtoolbar.menu.' + tabId,
            style : {
                overflow : 'visible'
            },
            items: [
                {
                    text    : 'Auto Width',
                    tooltip : {text : 'Adjust all column widths in grid based on data length'},
                    handler : function(widget, event) {
                        setColWidth(tabId);
                    }
                },
                {
                    text    : 'Remove Hidden Columns',
                    tooltip : {text : 'Remove hidden columns from grid view. Saved views only.'},
                    handler : function(widget, event) {
                        var arrayId   = tabId.split('.');

                        var dbName    = arrayId[0];
                        var schema    = arrayId[1];
                        var tableName = arrayId[2];
                        var taskName  = arrayId[3];

                        if (taskName) {
                            var colObj     = [];
                            var encodedObj = {};
                            var columns    = Ext.getCmp('grid.panel.' + tabId).columns;
                            var filters    = Ext.getCmp('grid.panel.' + tabId).filters.getFilterData();

                            var filterObj = {};
                            for (var i = 0; i < filters.length; i++) {
                                filterObj[filters[i].field] = {type : filters[i].data.type, value : filters[i].data.value};
                            }

                            for (var i = 0; i < columns.length; i++) {

                                var hidden = columns[i].hidden;

                                if (hidden == true) {
                                   continue;
                                }

                                var sortState = columns[i].sortState;
                                var stateId   = columns[i].stateId;
                                var colName   = columns[i].dataIndex;

                                var width     = columns[i].width;
                                var colDef    = {"id" : stateId, "width" : width, "name" : colName};

                                if (sortState) {
                                    colDef.sort = sortState;
                                }
                                if (hidden) {
                                    colDef.hidden = hidden;
                                }
                                if (filterObj[colName] != null) {
                                    colDef.filter     = filterObj[colName].value;
                                    colDef.filtertype = filterObj[colName].type;
                                }

                                colObj.push(colDef);
                            }

                            encodedObj.columns = colObj;
                            if (Ext.getCmp('aggregate.checkbox.' + tabId).getValue()) {
                                encodedObj.aggregate = true;
                            }
                            encodedObj = Ext.encode(encodedObj);

                            Ext.Ajax.request({
                                url       : 'extjs-store.php',
                                params    : {type : 'grid', op : 'put', key : tabId, data : encodedObj, remove_columns : true},
                                autoAbort : false,
                                success : function(response){
                                    Ext.Ajax.request({
                                        url       : 'extjs-table-def.php',
                                        params    : {database : dbName, schema : schema, table : tableName, view : tabId},
                                        autoAbort : false,
                                        success : function(response){
                                            var jsonObj        = Ext.JSON.decode (response.responseText);

                                            var aggChecked = false;
                                            if (jsonObj.aggregate) {
                                                aggChecked = true;
                                            }

                                            var results        = {};
                                            var columnArray    = getTableDefCols (jsonObj, results);
                                            var tableDataStore = getTableDataStore (jsonObj, tabId, dbName, schema, results, aggChecked);
                                            var gridView       = Ext.getCmp('grid.panel.' + tabId);

                                            gridView.reconfigure(tableDataStore, columnArray);

                                            //There was no "filter" parameter in a request anymore after reconfigure.
                                            //This is the fix for a bug.
                                            gridView.filters.bindStore(tableDataStore);

                                            Ext.getCmp('paging.toolbar.' + tabId).bindStore(tableDataStore);

                                            setColWidth(tabId);
                                        }
                                    });
                                },
                                failure: function(response, opts) {
                                    Ext.MessageBox.show({
                                        title   : 'Status',
                                        msg     : 'server-side failure with status code ' + response.status,
                                        buttons : Ext.MessageBox.OK
                                    });
                                }
                            });
                        }
                        else {
                             Ext.MessageBox.show({
                                 title   : 'Status',
                                 msg     : 'You can only remove columns from a saved view.',
                                 buttons : Ext.MessageBox.OK
                             });
                        }
                    }
                }
            ]
        });

        return(gridMenu);
    }

    function createAggregateCheckbox (tabId, aggChecked) {
        var aggregateCheckbox = Ext.create('Ext.form.field.Checkbox', {
            id            : 'aggregate.checkbox.' + tabId,
            boxLabel      : 'Aggregate',
            boxLabelAlign : 'before',
            labelAlign    : 'right',
            labelPad      : 3,
            checked       : aggChecked,
            handler : function(obj){

                var arrayId   = tabId.split('.');
                var dbName    = arrayId[0];
                var schema    = arrayId[1];
                var tableName = arrayId[2];

                if (obj.getValue()) {
                    Ext.Ajax.request({
                        url       : 'extjs-table-def.php',
                        params    : {database : dbName, schema : schema, table : tableName, view : tabId, aggregate : true},
                        autoAbort : false,
                        success : function(response, opts) {
                            var jsonObj = Ext.JSON.decode (response.responseText);

                            var results        = {};
                            var columnArray    = getTableDefCols (jsonObj, results);
                            var tableDataStore = getTableDataStore (jsonObj, tabId, dbName, schema, results);
                            var gridView       = Ext.getCmp('grid.panel.' + tabId);

                            tableDataStore.proxy.extraParams['aggregate'] = true;

                            gridView.reconfigure(tableDataStore, columnArray);

                            //There was no "filter" parameter in a request anymore after reconfigure.
                            //This is the fix for a bug.
                            gridView.filters.bindStore(tableDataStore);

                            Ext.getCmp('paging.toolbar.' + tabId).bindStore(tableDataStore);

                            setColWidth(tabId);

                            var columns     = gridView.columns;
                            var visibleCols = []
                            for (var i = 0; i < columns.length; i++) {
                                var hidden = columns[i].hidden;
                                if (!hidden) {
                                    visibleCols.push(columns[i].dataIndex);
                                }
                            }

                            tableDataStore.proxy.extraParams['visible_columns'] = visibleCols.join(",");
                        }
                    })
                }
                else {
                    Ext.Ajax.request({
                        url       : 'extjs-table-def.php',
                        params    : {database : dbName, schema : schema, table : tableName, view : tabId, aggregate : false},
                        autoAbort : false,
                        success : function(response, opts) {
                            var jsonObj = Ext.JSON.decode (response.responseText);

                            var results        = {};
                            var columnArray    = getTableDefCols (jsonObj, results);
                            var tableDataStore = getTableDataStore (jsonObj, tabId, dbName, schema, results);
                            var gridView       = Ext.getCmp('grid.panel.' + tabId);

                            tableDataStore.proxy.extraParams['aggregate'] = false;

                            gridView.reconfigure(tableDataStore, columnArray);

                            //There was no "filter" parameter in a request anymore after reconfigure.
                            //This is the fix for a bug.
                            gridView.filters.bindStore(tableDataStore);

                            Ext.getCmp('paging.toolbar.' + tabId).bindStore(tableDataStore);

                            setColWidth(tabId);

                            var columns     = gridView.columns;
                            var visibleCols = []
                            for (var i = 0; i < columns.length; i++) {
                                var hidden = columns[i].hidden;
                                if (!hidden) {
                                    visibleCols.push(columns[i].dataIndex);
                                }
                            }

                            tableDataStore.proxy.extraParams['visible_columns'] = visibleCols.join(",");
                        }
                    })
                }
            }
        });

        return(aggregateCheckbox);
    }

    function createGridMenuButton (gridMenu) {
        var gridMenuButton = Ext.create('Ext.Action', {
            icon : 'images/grid.png',
            menu : gridMenu
        });

        return(gridMenuButton);
    }

    function createGridComboBox (relationship, relationships, tabId) {
        var GridComboStoreData = [];
        if (relationship != null) {
            for (var i = 0; i < relationships.length; i++) {
                var array = [];
                var label = relationship[relationships[i]].relationship_label;
                var value = relationship[relationships[i]].relationship_alias;
                array.push(value);
                array.push(label);
                GridComboStoreData.push(array);
            }
        }

        var gridComboBox = {};

        if (GridComboStoreData.length > 0) {

            var gridComboStore = Ext.create('Ext.data.ArrayStore', {
                fields : ['value', 'label'],
                data   : GridComboStoreData
            });

            gridComboBox = Ext.create('Ext.form.field.ComboBox', {
                id           : 'relationship.combo.' + tabId,
                fieldLabel   : 'Add Columns',
                multiSelect  : true,
                labelAlign   : 'right',
                labelPad     : 3,
                displayField : 'label',
                valueField   : 'value',
                width        : 275,
                store        : gridComboStore,
                listeners : {
                    'change': function () {
                        var arrayId   = tabId.split('.');
                        var dbName    = arrayId[0];
                        var schema    = arrayId[1];
                        var tableName = arrayId[2];

                        Ext.Ajax.request({
                            url       : 'extjs-table-def.php',
                            params    : {database : dbName, schema : schema, table : tableName, relationships : gridComboBox.getValue().join(","), view : tabId},
                            autoAbort : false,
                            success : function(response){
                                var jsonObj = Ext.JSON.decode (response.responseText);

                                var aggChecked = false;
                                if (jsonObj.aggregate) {
                                    aggChecked = true;
                                }

                                var results        = {};
                                var columnArray    = getTableDefCols (jsonObj, results);
                                var tableDataStore = getTableDataStore (jsonObj, tabId, dbName, schema, results, aggChecked);
                                var gridView       = Ext.getCmp('grid.panel.' + tabId);

                                gridView.reconfigure(tableDataStore, columnArray);

                                //There was no "filter" parameter in a request anymore after reconfigure.
                                //This is the fix for a bug.
                                gridView.filters.bindStore(tableDataStore);

                                Ext.getCmp('paging.toolbar.' + tabId).bindStore(tableDataStore);

                                setColWidth(tabId);
                            }
                        });
                    }
                }
            });
        }
        return(gridComboBox);
    }

    function createTableGrid (tabId, tableDataStore, columnArray, gridSaveButton, gridSaveAsButton, gridTaskButton, gridMenuButton, gridComboBox, gridAggCheckbox, gridSqlButton, gridFormatComboMenu, gridCustomLabelMenu, gridExportMenu, results) {
        var tableGrid = Ext.create( 'Ext.grid.Panel',{
            id          : 'grid.panel.' + tabId,
            store       : tableDataStore,
            columns     : columnArray,
            autoScroll  : true,
            stripeRows  : true,
            columnLines : true,
            features    : [filters],
            dockedItems : [{
                xtype : 'toolbar',
                id    : 'toolbar.grid.panel.' + tabId,
                items : [
                    gridSaveButton,
                    gridSaveAsButton,
                    gridTaskButton,
                    gridSqlButton,
                    gridMenuButton,
                    gridAggCheckbox,
                    //gridComboBox,
                    gridExportMenu
                ]
            }],
            listeners: {
                viewready : function() {
                    if (results == null || results.doAutoColWidth) {
                        setColWidth(tabId);
                    }
                },
                afterrender: function(obj) {
                    // Normally the gridpanel filter feature menus do not get created
                    // until a user physically clicks on one of them.
                    // To handle this you can explicitly create them in the gridpanel's afterrender event
                    // so that they are available right away. thanks Geronimo, go falcons.
                    obj.filters.createFilters();

                    var menu = this.headerCt.getMenu();
                    menu.add([
                        {
                            icon : 'images/columns.gif',
                            text : 'Column Label',
                            menu : [gridCustomLabelMenu]
                        },
                        {
                            icon : 'images/columns.gif',
                            text : 'Format Data',
                            menu : [gridFormatComboMenu]
                        }
                    ]);
                },
                columnhide : function(ct, column, obj) {
                    if (Ext.getCmp('aggregate.checkbox.' + tabId).getValue()) {

                        var store   = Ext.getCmp('grid.panel.' + tabId).getStore();
                        var columns = Ext.getCmp('grid.panel.' + tabId).columns;

                        var visibleCols = []
                        for (var i = 0; i < columns.length; i++) {
                            var hidden = columns[i].hidden;
                            if (!hidden) {
                                visibleCols.push(columns[i].dataIndex);
                            }
                        }

                        store.proxy.extraParams['visible_columns'] = visibleCols.join(",");
                        store.reload();
                    }
                },
                columnshow : function(ct, column, obj) {
                    if (Ext.getCmp('aggregate.checkbox.' + tabId).getValue()) {

                        var store   = Ext.getCmp('grid.panel.' + tabId).getStore();
                        var columns = Ext.getCmp('grid.panel.' + tabId).columns;

                        var visibleCols = []
                        for (var i = 0; i < columns.length; i++) {
                            var hidden = columns[i].hidden;
                            if (!hidden) {
                                visibleCols.push(columns[i].dataIndex);
                            }
                        }

                        store.proxy.extraParams['visible_columns'] = visibleCols.join(",");
                        store.reload();
                    }
                }
            },
            viewConfig : {
                enableTextSelection: true
            }
        });

        return(tableGrid);
    }

    function addTab(tabId) {
        var tabPanel  = Ext.getCmp('vp-region-tabpanel');
        var arrayId   = tabId.split('.');

        var dbName    = arrayId[0];
        var schema    = arrayId[1];
        var tableName = arrayId[2];

        if (Ext.getCmp(tabId) === undefined) {

            Ext.Ajax.request({
                url       : 'extjs-table-def.php',
                params    : {database : dbName, schema : schema, table : tableName, view : tabId},
                autoAbort : false,
                success : function(response, opts){
                    var jsonObj = Ext.JSON.decode(response.responseText);

                    var aggChecked = false;
                    if (jsonObj.aggregate) {
                        aggChecked = true;
                    }

                    var results = {};
                    results.id = tabId;

                    var columnArray = getTableDefCols(jsonObj, results);

                    var relationship  = {};
                    var relationships = [];
                    getTableDefRels(jsonObj, relationship, relationships);

                    var gridSaveButton       = createGridSaveButton (tabId);
                    var gridTaskButton       = createGridTaskButton (tabId, jsonObj.table_label);
                    var gridSaveAsButton     = createGridSaveAsButton (tabId);
                    var gridSqlButton        = createGridSqlButton (tabId);
                    var gridMenu             = createGridMenu (tabId);
                    var gridMenuButton       = createGridMenuButton (gridMenu);
                    var gridComboBox         = createGridComboBox (relationship, relationships, tabId);
                    var gridAggCheckbox      = createAggregateCheckbox (tabId, aggChecked);
                    var gridFormatComboMenu  = createFormatComboMenu (tabId, results);
                    var gridCustomLabelMenu  = createCustomLabelMenu (tabId);
                    var gridExportMenu       = createExportMenu (tabId);
                    var gridExportMenuButton = createExportMenuButton(gridExportMenu);

                    var tableDataStore;
                    var columnArray;
                    var tableGrid;

                    if (jsonObj.sql) {
                        tableDataStore = getTableDataStoreSql (jsonObj, tabId, dbName, schema, results);
                        columnArray    = getTableDefColsSql (jsonObj, results);
                        tableGrid      = createTableGrid (tabId, tableDataStore, columnArray, gridSaveButton, gridSaveAsButton, gridTaskButton, gridMenuButton, {}, {}, gridSqlButton, gridFormatComboMenu, gridCustomLabelMenu, gridExportMenuButton, results);
                    }
                    else {
                        tableDataStore = getTableDataStore (jsonObj, tabId, dbName, schema, results, aggChecked);
                        columnArray    = getTableDefCols (jsonObj, results);
                        tableGrid      = createTableGrid (tabId, tableDataStore, columnArray, gridSaveButton, gridSaveAsButton, gridTaskButton, gridMenuButton, gridComboBox, gridAggCheckbox, gridSqlButton, gridFormatComboMenu, gridCustomLabelMenu, gridExportMenuButton, results);
                    }

                    var changePageSizeCombo = Ext.create ('Ext.form.ComboBox',{
                        id           : 'change.pagesize.' + tabId,
                        fieldLabel   : 'Page Size',
                        labelAlign   : 'right',
                        labelWidth   : 75,
                        labelPad     : 3,
                        width        : 140,
                        value        : GridItemsPerPage,
                        displayField : 'id',
                        valueField   : 'id',
                        store : Ext.create('Ext.data.ArrayStore',{
                          fields : ['id'],
                          data   : [['5'],['15'],['25'],['50'],['100'],['150'],['300']]
                        }),
                        listeners : {
                            select : function (obj, records, eOpts ) {
                                var store      = Ext.getCmp('grid.panel.' + tabId).getStore();
                                store.pageSize = parseInt(obj.value, 10);
                                Ext.getCmp('paging.toolbar.' + tabId).doRefresh();
                            }
                        }
                    });

                    tabPanel.add({
                        title      : jsonObj.table_label,
                        closable   : true,
                        id         : tabId,
                        //autoScroll : true,
                        layout     : 'fit',
                        items    : [
                            tableGrid
                        ],
                        listeners : {
                            close : function() {
                                if (Ext.getCmp(tabId) != null) {
                                    Ext.getCmp('accordion.info.panel').remove(Ext.getCmp('info.panel.' + tabId));
                                    tabTimeCreatedCache[tabId] = null;
                                }
                            }
                        },
                        dockedItems: [{
                            xtype       : 'pagingtoolbar',
                            id          : 'paging.toolbar.' + tabId,
                            store       : tableDataStore,
                            dock        : 'bottom',
                            displayInfo : true,
                            items : [
                                changePageSizeCombo
                            ]
                        }]
                    });

                    tabPanel.setActiveTab(tabId);

                    var info = Ext.getCmp('accordion.info.panel');
                    info.add(Ext.create('Ext.Panel',{
                        title      : jsonObj.table_label,
                        id         : 'info.panel.' + tabId,
                        autoScroll : true,
                        listeners  : {
                            afterrender : function(obj){
                                Ext.Ajax.request({
                                    url       : 'extjs-store.php',
                                    params    : {type : 'help', op : 'get', key : tabId},
                                    autoAbort : false,
                                    success : function(response){
                                        Ext.getCmp('info.panel.' + tabId).update(response.responseText);
                                    },
                                    failure: function(response, opts) {
                                        Ext.MessageBox.show({
                                           title   : 'Status',
                                           msg     : 'server-side failure with status code ' + response.status,
                                           buttons : Ext.MessageBox.OK
                                        });
                                    }
                                });
                            }
                        },
                        tools : [{
                            type : 'edit',
                            handler : function(event, toolEl, panel){
                                Ext.create('Ext.window.Window', {
                                    xtype  : 'panel',
                                    title  : 'Message / Info Editor - ' + Ext.getCmp('info.panel.' + tabId).title,
                                    width  : 550,
                                    height : 250,
                                    frame  : true,
                                    layout : 'fit',
                                    shadowOffset : 25,
                                    tools  : [{
                                        type    : 'save',
                                        handler : function(event, toolEl, panel){
                                            var content = Ext.getCmp('info.panel.htmledit.' + tabId).getValue();
                                            Ext.getCmp('info.panel.' + tabId).update(content);

                                            Ext.Ajax.request({
                                                url       : 'extjs-store.php',
                                                params    : {type : 'help', op : 'put', key : tabId, data :content},
                                                autoAbort : false,
                                                success : function(response){
                                                    Ext.MessageBox.show({
                                                       title   : 'Status',
                                                       msg     : 'Changes saved successfully.',
                                                       buttons : Ext.MessageBox.OK
                                                    });
                                                },
                                                failure: function(response, opts) {
                                                    Ext.MessageBox.show({
                                                       title   : 'Status',
                                                       msg     : 'server-side failure with status code ' + response.status,
                                                       buttons : Ext.MessageBox.OK
                                                    });
                                                }
                                            });
                                        }
                                    }],
                                    items : {
                                        xtype            : 'htmleditor',
                                        id               : 'info.panel.htmledit.' + tabId,
                                        enableColors     : true,
                                        enableAlignments : true
                                    }
                                }).show();

                                if (Ext.getCmp('info.panel.' + tabId).body.dom.innerHTML != null) {
                                    Ext.getCmp('info.panel.htmledit.' + tabId).setValue(Ext.getCmp('info.panel.' + tabId).body.dom.innerHTML);
                                }
                            }
                        }]
                    }));
                    Ext.getCmp('info.panel.' + tabId).expand();
                },
            });
        }

        tabPanel.setActiveTab(tabId);
    }

    // table tree store
    var tableTreeStore = Ext.create('Ext.data.TreeStore', {
        storeId  : 'table.tree.store',
        autoLoad : true,
        proxy : {
            type : 'ajax',
            url  : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/tabletree',
            extraParams: {
                mode : 'getTree'
            },
            actionMethods : 'POST'
        },
        root: {
            text     : 'Tree',
            id       : 'src',
            expanded : true
        }
    });

    tableTreeContextMenu = new Ext.menu.Menu({
        items: [
            { id: 'table.tree.menu.delete', text: 'Delete' }
        ],
        listeners: {
            click: function(menu, item, e, eopts) {
                if (FrontSuite.session.lastTableTreeIdClicked) {
                    var tableNodeId, tableParentId, tableLeaf;
                    tableNodeId   = FrontSuite.session.lastTableTreeIdClicked;
                    tableParentId = FrontSuite.session.lastTableParentIdClicked;
                    tableLeaf     = FrontSuite.session.lastTableLeafClicked;

                    if (tableLeaf == true) {
                        Ext.Ajax.request({
                            url       : 'extjs-store.php',
                            params    : {type : 'grid', op : 'delete', key : tableNodeId},
                            autoAbort : false,
                            success : function(response){
                                var selectedNode = Ext.getCmp('table.tree.panel').getSelectionModel().getSelection()[0];
                                selectedNode.remove();
                            },
                            failure: function(response, opts) {
                                Ext.MessageBox.show({
                                   title   : 'Status',
                                   msg     : 'server-side failure with status code ' + response.status,
                                   buttons : Ext.MessageBox.OK
                                });
                            }
                        });
                    }

                    FrontSuite.session.lastTableTreeIdClicked = null;
                }
            }
        }
    });

    // tree panel for tables
    var tableTreePanel = Ext.create('Ext.tree.Panel', {
        id           : 'table.tree.panel',
        scroll       : false,
        bodyStyle    : {border:0},
        useArrows    : true,
        rootVisible  : false,
        store        : tableTreeStore,
        listeners    : {
            itemclick : function(view, rec, item, index, eventObj) {
                var id      = rec.data.id;
                var arrayId = id.split('.');

                var firstTime = 0;
                if (!tabTimeCreatedCache[id]) {
                    var t     = new Date();
                    firstTime = 1;
                    tabTimeCreatedCache[id] = t;
                }

                if (arrayId.length >= 3) {
                    var t = new Date();
                    var secondsDiff = (t - tabTimeCreatedCache[id]) / 1000;
                    if (firstTime || secondsDiff > 90) {
                        addTab(rec.get('id'));
                        tabTimeCreatedCache[id] = t;
                    }
                }
            },
            itemcontextmenu: function(view, rec, node, index, e) {
                e.stopEvent();
                tableTreeContextMenu.showAt(e.getXY());
                FrontSuite.session.lastTableTreeIdClicked   = rec.data.id;
                FrontSuite.session.lastTableParentIdClicked = rec.parentNode.data.id;
                FrontSuite.session.lastTableLeafClicked     = rec.data.leaf;
                return false;
            }
        }
    });

    // panel for data importing
    var dataImportTreePanel = Ext.create('Ext.tree.Panel', {
        id           : 'dataImport.tree.panel',
        scroll       : false,
        bodyStyle    : {border:0},
        useArrows    : true,
        rootVisible  : false,
        //store        : tableTreeStore,
        listeners    : {
            itemclick : function(view, rec, item, index, eventObj) {
                console.log("data import tree panel clicked");
            },

        }
    });

    // panel for reporting
    var reportingTreePanel = Ext.create('Ext.tree.Panel', {
        id           : 'reporting.tree.panel',
        scroll       : false,
        bodyStyle    : {border:0},
        useArrows    : true,
        rootVisible  : false,
        //store        : tableTreeStore,
        listeners    : {
            itemclick : function(view, rec, item, index, eventObj) {
                console.log("reporting tree panel clicked");
            },
        }
    });

    // screen tree store
    var documentTreeStore = Ext.create('Ext.data.TreeStore', {
        storeId  : 'document.tree.store',
        autoLoad : true,
        //autoSync : true,
        //model    : 'ActionTreeModel',
        proxy : {
            type : 'ajax',
            url  : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/filetree',
            extraParams: { mode : 'getTree' },
            actionMethods : 'POST',
        },
        root: {
            text     : 'Files',
            id       : 'src',
            expanded : true
        }
    });

    function storeExpandedDocumentTreeNodes () {
        var nodes = documentTreeStore.tree.nodeHash;
        for (var key in nodes) {
            if (key == "src")
                continue;
            if (nodes[key].raw.leaf == undefined && nodes[key].data.expanded == true)
                documentTreePanel.expNodes.push(key);
        }
    }

    function createFormModalDialog (form) {
        var dialog = Ext.create("Ext.Window", {
            title : 'Create Database',
            modal : true,
            // closable : false,
            items: [ form ]
        });
        return(dialog);
    }

    function createFormPanelFromTable (database, schema, table, url) {
        var form = Ext.create("Ext.form.Panel", {
            'url': url,
            frame: true,
            // title: 'Simple Form',
            bodyStyle:'padding:5px 5px 0',
            width: 350,
            fieldDefaults: {
                msgTarget: 'side',
                labelWidth: 75
            },
            defaultType: 'textfield',
            defaults: {
                anchor: '100%'
            },

            items: [{
                fieldLabel: 'First Name',
                name: 'first',
                allowBlank:false
            },{
                fieldLabel: 'Last Name',
                name: 'last'
            },{
                fieldLabel: 'Company',
                name: 'company'
            }, {
                fieldLabel: 'Email',
                name: 'email',
                vtype:'email'
            }, {
                xtype: 'timefield',
                fieldLabel: 'Time',
                name: 'time',
                minValue: '8:00am',
                maxValue: '6:00pm'
            }],

            buttons: [{
                text: 'Save'
            },{
                text: 'Cancel'
            }]
        });
        return(form);
    }

    // panel for documents
    var documentTreePanel = Ext.create('Ext.tree.Panel', {
        id           : 'document.tree.panel',
        scroll       : false,
        bodyStyle    : {border:0},
        useArrows    : true,
        rootVisible  : false,
        store        : documentTreeStore,
        expNodes     : [],
        sortOnDrop   : true,
        listeners    : {
            itemcontextmenu: function(view, rec, node, index, e) {
                console.log(documentTreePanel);
                e.stopEvent();
                documentTreeContextMenu.showAt(e.getXY());
                FrontSuite.session.lastTaskDocumentIdClicked       = rec.data.id;
                FrontSuite.session.lastTaskDocumentParentIdClicked = rec.parentNode.data.id;
                FrontSuite.session.lastTaskDocumentLeafClicked     = rec.data.leaf;
                return false;
            },
            load : function () {
                // expand any nodes that were expanded before a reload
                var rootNode = documentTreePanel.getRootNode();
                for (var idx = 0; idx < documentTreePanel.expNodes.length; idx++) {
                    if ( (node = rootNode.findChild('id', documentTreePanel.expNodes[idx], true)) ){ // renamed nodes will no longer exist
                        node.expand(false);
                    }
                }
            },
        },
        viewConfig : {
            plugins    : {
                ptype : 'treeviewdragdrop'
            },
            //sortOnDrop : true,
            listeners  : {
                beforedrop : function(newParentHtml , oldParent, newParent, operation, eOpts) {
                    if (screenTreeStore.isLoading()) {
                        console.log("need to handle is loading case");
                    }
                    else {
                        //for (var i = 0; i < data.records.length; i++) {
                            var from  = oldParent.records[0].internalId;
                            var to    = (newParent.raw.id == 'src') ? '.' : newParent.internalId;
                            var isDir = (oldParent.records[0].raw.leaf == undefined);

                            // TODO: figure out how to disable inserts with drag and drop
                            if (operation != 'append'){
                                if ( isDir ){
                                    if ( /\//.test(to) )
                                        to = to.replace(/[^\/]+[\/]{0,1}$/,"");
                                    else
                                        to = ".";
                                }
                                else {
                                    if ( newParent.parentNode.parentNode == null) {
                                        to = '.';
                                    }
                                    else if ( /\/[^\/]+$/.test(to) ) {
                                        if (newParent.raw.leaf == undefined){
                                            to = to.replace(/\/[^\/]+$/,"");
                                        }
                                        else {
                                            //to = to.replace(/\/[^\/]+\/[^\/]+$/,"");
                                            to = to.replace(/\/[^\/]+$/,"");
                                        }
                                    }
                                }
                            }

                            Ext.Ajax.request({
                                url       : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/filetree',
                                params    : { op : 'move', from : from, to : to },
                                autoAbort : false,
                                success : function(response){
                                    if (Ext.decode(response.responseText).success){
                                        //node.expand(); // TODO: get this to render correctly on reload
                                        // TODO: update moved node such that we can remove the need for a reload
                                        storeExpandedDocumentTreeNodes();
                                        documentTreeStore.reload();
                                    }
                                    else {
                                        return false;
                                    }
                                },
                                failure: function(response, opts) {
                                    Ext.MessageBox.show({
                                       title   : 'Status',
                                       msg     : 'server-side failure with status code ' + response.status,
                                       buttons : Ext.MessageBox.OK
                                    });
                                    return false;
                                }
                            });

                        //}
                    }
                },
            },

        },
    });

    documentTreeContextMenu = new Ext.menu.Menu({
        items: [
            // { id: 'document.tree.menu.mkdir',    text: 'Add Folder' },
            // { id: 'document.tree.menu.rename',   text: 'Rename' },
            // { id: 'document.tree.menu.delete',   text: 'Delete' },
            // { xtype: Ext.menu.Separator },
            // { id: 'document.tree.menu.download', text: 'Download (todo)' },
            // { id: 'document.tree.menu.share',    text: 'Share Link (todo)' },
            // { xtype: Ext.menu.Separator }, // some test functionality
            // { id: 'document.tree.menu.printNode', text: '**console.log(thisNode)**'},
            // { id: 'document.tree.menu.testAlert', text: '**generate alert**'}
        ],
        listeners: {
            click: function(menu, item, e, eopts) {
                if (FrontSuite.session.lastTaskDocumentIdClicked) {
                    var taskNodeId, taskParentId, taskLeaf;
                    taskNodeId   = FrontSuite.session.lastTaskDocumentIdClicked;
                    taskParentId = FrontSuite.session.lastTaskDocumentParentIdClicked;
                    taskLeaf     = FrontSuite.session.lastTaskDocumentLeafClicked;

                    switch (item.id) {
                        case 'document.tree.menu.printNode':
                            console.log("User Selected Node:");
                            console.log(Ext.getCmp('document.tree.panel').getSelectionModel().getSelection()[0]);
                        break;
                        case 'document.tree.menu.testAlert':
                            generateAlert("title here", "this is a test message");
                        break;

                        case 'document.tree.menu.mkdir':
                        case 'document.tree.menu.rename':

                            promptTitle = "Add Folder";
                            promptText  = "Please enter folder name: ";

                            if (item.id == 'document.tree.menu.rename') {
                                promptTitle = "Rename";
                                promptText  = "Please enter new name: ";
                            }

                            Ext.MessageBox.prompt(promptTitle, promptText, function(btn, folderVal){
                                if (btn == 'ok'){
                                    node = Ext.getCmp('document.tree.panel').getSelectionModel().getSelection()[0];

                                    if (item.id == 'document.tree.menu.mkdir')
                                        paramSet = { op : 'mkdir', dir_path : node.internalId, dir_name : folderVal};
                                    else
                                        paramSet = { op : 'rename', from : node.internalId, to : folderVal };

                                    Ext.Ajax.request({
                                        url       : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/filetree',
                                        params    : paramSet,
                                        autoAbort : false,
                                        success   : function(response) {
                                            if (Ext.decode(response.responseText).success){
                                                //node.expand(); // TODO: get this to render correctly on reload
                                                storeExpandedDocumentTreeNodes();

                                                // TODO: find old name in expNodes list and rename it to new name

                                                documentTreeStore.reload();

                                            }
                                            else {
                                                if ( Ext.decode(response.responseText).msg != undefined) {
                                                    Ext.MessageBox.show({
                                                        title   : "Error - could not " + ((item.id == 'document.tree.menu.mkdir') ? "make" : "rename") + " item",
                                                        msg     : Ext.decode(response.responseText).msg,
                                                        buttons : Ext.MessageBox.OK
                                                    });
                                                }
                                            }
                                        },
                                        failure: function(response, opts) {
                                            Ext.MessageBox.show({
                                               title   : 'Status',
                                               msg     : 'server-side failure with status code ' + response.status,
                                               buttons : Ext.MessageBox.OK
                                            });
                                        }
                                    });
                                }
                             });
                            break;
                        case 'document.tree.menu.delete':
                            file       = Ext.getCmp('document.tree.panel').getSelectionModel().getSelection()[0].internalId;
                            ajaxParams = { op : 'delete', dir_path : file };
                            isDir      = !(Ext.getCmp('document.tree.panel').getSelectionModel().getSelection()[0].data.leaf);
                            msg        = 'Please confirm';

                            if (isDir)
                                msg +=  " (folder contents will also be deleted)";

                            Ext.MessageBox.show({
                                title   : "Permanently delete " + file + "?",
                                msg     : msg,
                                buttons : Ext.MessageBox.OKCANCEL,
                                animateTarget : this,
                                autoRender : true,
                                fn: function(btn) {
                                    if( btn == 'ok') {
                                        ajaxParams['force'] = 1;

                                        Ext.Ajax.request({
                                            url       : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/filetree',
                                            params    : ajaxParams,
                                            autoAbort : false,
                                            success : function(response){
                                                jsonResponse = Ext.decode(response.responseText);
                                                if (jsonResponse.success){
                                                    Ext.getCmp('document.tree.panel').getSelectionModel().getSelection()[0].remove();
                                                }
                                                else if ( jsonResponse.msg != undefined) {
                                                    Ext.MessageBox.show({
                                                        title   : "Error - could not delete " + ((isDir) ? "directory" : "file"),
                                                        msg     : jsonResponse.msg,
                                                        buttons : Ext.MessageBox.OK
                                                    });
                                                }
                                            },
                                            failure: function(response, opts) {
                                                Ext.MessageBox.show({
                                                   title   : 'Status',
                                                   msg     : 'server-side failure with status code ' + response.status,
                                                   buttons : Ext.MessageBox.OK
                                                });
                                            }
                                        });
                                    }
                                }
                            });

                            break;
                            default :
                                console.log("unknown event");
                            break;
                    }

                    FrontSuite.session.lastTaskDocumentIdClicked = null;
                }
            }
        }
    });

    Ext.define('ActionTreeModel', {
        extend : 'Ext.data.Model',
        fields : [
            {name : 'text',   type : 'string'}, // this is the label text. it exists in the base model and must be preserved in this new model.
            {name : 'action', type : 'string'}  // this is the new field.
        ]
    });
    Ext.data.NodeInterface.decorate("ActionTreeModel");

    screenTreeContextMenu = Ext.create('Ext.menu.Menu',{
        items: [
            { id: 'screen.tree.menu.delete', text: 'Delete' },
            { id: 'screen.tree.menu.add',    text: 'Add Folder' }
        ],
        listeners: {
            click: function(menu, item, e, eopts) {

                if (FrontSuite.session.lastTaskTreeIdClicked) {
                    var taskNodeId, taskParentId, taskLeaf;
                    taskNodeId   = FrontSuite.session.lastTaskTreeIdClicked;
                    taskParentId = FrontSuite.session.lastTaskParentIdClicked;
                    taskLeaf     = FrontSuite.session.lastTaskLeafClicked;

                    switch (item.id) {
                        case 'screen.tree.menu.delete':
                            Ext.Ajax.request({
                                url       : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/apptree',
                                params    : {type : 'screens', op : 'delete', tree_node_id : taskNodeId},
                                autoAbort : false,
                                success : function(response){
                                    var selectedNode = Ext.getCmp('screen.tree.panel').getSelectionModel().getSelection()[0];
                                    selectedNode.remove();
                                },
                                failure: function(response, opts) {
                                    Ext.MessageBox.show({
                                       title   : 'Status',
                                       msg     : 'server-side failure with status code ' + response.status,
                                       buttons : Ext.MessageBox.OK
                                    });
                                }
                            });

                            break;
                        case 'screen.tree.menu.add':
                            Ext.MessageBox.prompt('Add Folder', 'Please enter folder text:', function(btn, folderVal){
                                if (btn == 'ok'){
                                    var params = {};
                                    var addedFolderNm = folderVal;
                                    if (taskLeaf) {
                                        params = {type : 'screens', op : 'new', parent_id : taskParentId, previous_sibling_id : taskNodeId, label : addedFolderNm};
                                    }
                                    else {
                                        params = {type : 'screens', op : 'new', drop_position : 'append', parent_id : taskNodeId, label : addedFolderNm};
                                    }

                                    Ext.Ajax.request({
                                        url       : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/apptree',
                                        params    : params,
                                        autoAbort : false,
                                        success : function(response){
                                            var jsonObj    = Ext.JSON.decode (response.responseText);
                                            var treeNodeId = jsonObj.tree_id;

                                            var selectedNode = Ext.getCmp('screen.tree.panel').getSelectionModel().getSelection()[0];
                                            if (selectedNode.data.leaf) {
                                                selectedNode.parentNode.insertBefore({
                                                    id     : treeNodeId,
                                                    text   : addedFolderNm,
                                                    leaf   : false,
                                                    action : null
                                                }, selectedNode);
                                            }
                                            else {
                                                var store = Ext.getCmp('screen.tree.panel').getStore();
                                                selectedNode.expand();
                                                if (selectedNode.store.treeStore.tree.nodeHash[treeNodeId] == null && store.isLoading() == false) {
                                                    selectedNode.appendChild({
                                                        id     : treeNodeId,
                                                        text   : addedFolderNm,
                                                        action : null,
                                                        leaf   : false
                                                    });
                                                }
                                            }
                                        },
                                        failure: function(response, opts) {
                                            Ext.MessageBox.show({
                                               title   : 'Status',
                                               msg     : 'server-side failure with status code ' + response.status,
                                               buttons : Ext.MessageBox.OK
                                            });
                                        }
                                    });
                                }
                            });
                            break;
                    }

                    FrontSuite.session.lastTaskTreeIdClicked = null;
                }
            }
        }
    });

    // screen tree store
    var screenTreeStore = Ext.create('Ext.data.TreeStore', {
        storeId  : 'screen.tree.store',
        autoLoad : true,
        model    : 'ActionTreeModel',
        proxy : {
            type : 'ajax',
            url  : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/apptree',
            extraParams: {
                mode : 'getTree',
                type : 'screens'
            },
            actionMethods : 'POST'
        },
        root: {
            text     : 'Tree',
            id       : 'src',
            expanded : true
        }
    });

    var screenTreePanel = Ext.create('Ext.tree.Panel', {
        id           : 'screen.tree.panel',
        bodyStyle    : {border:0},
        scroll       : false,
        useArrows    : true,
        rootVisible  : false,
        store        : screenTreeStore,
        viewConfig : {
            plugins : {
                ptype : 'treeviewdragdrop'
            },
            listeners : {
                drop : function(htmlNodeBelow, data, model, dropPos, obj) {

                    var isLoading = screenTreeStore.isLoading();

                    if (isLoading) {
                        for (var i = 0; i < data.records.length; i++) {

                            var treeNodeId = data.records[i].data.id;
                            var parentId   = model.internalId;

                            //console.log('treeNodeId: ' + treeNodeId + ' ,parentId: ' + parentId  + ' ,dropPos: ' + dropPos);

                            Ext.Ajax.request({
                                url       : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/apptree',
                                params    : {type : 'screens', op : 'move', drop_position : dropPos, tree_node_id : treeNodeId, parent_id : parentId},
                                autoAbort : false,
                                success : function(response){
                                },
                                failure: function(response, opts) {
                                    Ext.MessageBox.show({
                                       title   : 'Status',
                                       msg     : 'server-side failure with status code ' + response.status,
                                       buttons : Ext.MessageBox.OK
                                    });
                                }
                            });
                        }
                    }
                    else {
                        for (var i = 0; i < data.records.length; i++) {

                            var treeNodeId        = data.records[i].data.id;
                            var parentId          = data.records[i].data.parentId;
                            var nextSiblingId     = data.records[i].nextSibling ? data.records[i].nextSibling.data.id : null;
                            var previousSiblingId = data.records[i].previousSibling ? data.records[i].previousSibling.data.id : null;

                            //console.log('treeNodeId: ' + treeNodeId + ' ,parentId: ' + parentId  + ' ,dropPos: ' + dropPos + ' ,nextSiblingId: ' + nextSiblingId + ' ,previousSiblingId: ' + previousSiblingId);

                            Ext.Ajax.request({
                                url       : FrontSuite.options.apps_urldir + '/sitefront/front-framework/api.php/service/ext/apptree',
                                params    : {type : 'screens', op : 'move', drop_position : dropPos, tree_node_id : treeNodeId, parent_id : parentId, next_sibling_id : nextSiblingId, previous_sibling_id : previousSiblingId},
                                autoAbort : false,
                                success : function(response){
                                },
                                failure: function(response, opts) {
                                    Ext.MessageBox.show({
                                       title   : 'Status',
                                       msg     : 'server-side failure with status code ' + response.status,
                                       buttons : Ext.MessageBox.OK
                                    });
                                }
                            });
                        }
                    }
                }
            }
        },
        listeners : {
            itemclick : function(view, rec, item, index, eventObj) {
                var firstTime = 0;
                var action = rec.data.action;

                if (action) {
                    if (!tabTimeCreatedCache[action]) {
                        var t     = new Date();
                        firstTime = 1;
                        tabTimeCreatedCache[action] = t;
                    }

                    var t = new Date();
                    var secondsDiff = (t - tabTimeCreatedCache[action]) / 1000;
                    if (firstTime || secondsDiff > 90) {
                        addTab(action);
                        tabTimeCreatedCache[action] = t;
                    }
                }

                //var action = rec.data.action;
                //if (action) {
                //    addTab(action);
                //}
            },
            itemcontextmenu: function(view, rec, node, index, e) {
                e.stopEvent();
                screenTreeContextMenu.showAt(e.getXY());
                FrontSuite.session.lastTaskTreeIdClicked   = rec.data.id;
                FrontSuite.session.lastTaskParentIdClicked = rec.parentNode.data.id;
                FrontSuite.session.lastTaskLeafClicked     = rec.data.leaf;
                return false;
            }
        }
        //dockedItems: [{
        //    xtype: 'toolbar',
        //    items: [{
        //        text: 'Expand All',
        //        handler: function(){
        //            screenTreePanel.getEl().mask('Expanding tree...');
        //            var toolbar = this.up('toolbar');
        //            toolbar.disable();
        //
        //            screenTreePanel.expandAll(function() {
        //                screenTreePanel.getEl().unmask();
        //                toolbar.enable();
        //            });
        //        }
        //    }, {
        //        text: 'Collapse All',
        //        handler: function(){
        //            var toolbar = this.up('toolbar');
        //            toolbar.disable();
        //
        //            screenTreePanel.collapseAll(function() {
        //                toolbar.enable();
        //            });
        //        }
        //    }]
        //}]
    });

    // accordion for navigation
    var navAccordion = new Ext.Panel({
        id : 'accordion.panel',
        defaults : {
            bodyStyle: 'padding:10px'
        },
        layout: {
            type          : 'accordion',
            titleCollapse : false,
            animate       : true,
            activeOnTop   : true
        },
        items: [
            {
                title      : 'Tasks',
                id         : 'tasks.panel',
                autoScroll : true,
                items : [
                    screenTreePanel
                ]
            },
            {
                title      : 'Tables',
                id         : 'tables.panel',
                autoScroll : true,
                items : [
                    tableTreePanel
                ]
            },
            {
                title      : 'Data Import',
                id         : 'dataImport.panel',
                autoScroll : true,
                items : [
                    dataImportTreePanel
                ]
            },
            {
                title      : 'Reporting',
                id         : 'reporting.panel',
                autoScroll : true,
                items : [
                    reportingTreePanel
                ]
            },
            {
                title      : 'Files',
                id         : 'document.panel',
                autoScroll : true,
                items : [
                    documentTreePanel
                ],
                tools:[
                    {
                        type:'refresh',
                        tooltip: 'Refresh file tree',
                        handler: function(event, toolEl, panel){
                            storeExpandedDocumentTreeNodes();
                            documentTreeStore.reload();
                       }
                   }
                ],
            }
        ]
    });

    var infoAccordion = new Ext.Panel({
        id : 'accordion.info.panel',
        defaults : {
            bodyStyle: 'padding:10px'
        },
        layout: {
            type          : 'accordion',
            titleCollapse : false,
            animate       : true,
            activeOnTop   : true
        },
        items: [
            {
                title      : 'General Help',
                id         : 'info.panel',
                autoScroll : true,
                listeners  : {
                    afterrender : function(obj){
                        Ext.Ajax.request({
                            url       : 'extjs-store.php',
                            params    : {type : 'help', op : 'get', key : 'general.help.panel'},
                            autoAbort : false,
                            success : function(response){
                                Ext.getCmp('info.panel').update(response.responseText);
                            },
                            failure: function(response, opts) {
                                Ext.MessageBox.show({
                                   title   : 'Status',
                                   msg     : 'server-side failure with status code ' + response.status,
                                   buttons : Ext.MessageBox.OK
                                });
                            }
                        });
                    }
                },
                tools : [{
                    type : 'edit',
                    handler : function(event, toolEl, panel){
                        Ext.create('Ext.window.Window', {
                            title  : 'Message / Info Editor - ' + Ext.getCmp('info.panel').title,
                            width  : 550,
                            height : 250,
                            frame  : true,
                            layout : 'fit',
                            shadowOffset : 25,
                            tools  : [{
                                type    : 'save',
                                handler : function(event, toolEl, panel){
                                    var content = Ext.getCmp('info.panel.htmledit').getValue();
                                    Ext.getCmp('info.panel').update(content);

                                    Ext.Ajax.request({
                                        url       : 'extjs-store.php',
                                        params    : {type : 'help', op : 'put', key : 'general.help.panel', data :content},
                                        autoAbort : false,
                                        success : function(response){
                                            Ext.MessageBox.show({
                                               title   : 'Status',
                                               msg     : 'Changes saved successfully.',
                                               buttons : Ext.MessageBox.OK
                                            });
                                        },
                                        failure: function(response, opts) {
                                            Ext.MessageBox.show({
                                               title   : 'Status',
                                               msg     : 'server-side failure with status code ' + response.status,
                                               buttons : Ext.MessageBox.OK
                                            });
                                        }
                                    });
                                }
                            }],
                            items : {
                                xtype            : 'htmleditor',
                                id               : 'info.panel.htmledit',
                                enableColors     : true,
                                enableAlignments : true
                            }
                        }).show();

                        if (Ext.getCmp('info.panel').body.dom.innerHTML != null) {
                            Ext.getCmp('info.panel.htmledit').setValue(Ext.getCmp('info.panel').body.dom.innerHTML);
                        }
                    }
                }]
            }
        ]
    });

    // viewport
    // PORTED
    var viewPort = Ext.create('Ext.container.Viewport', {
        id     : 'viewport.border',
        layout : 'border',
        items : [{
            region  : 'north',
            id      : 'vp-region-header',
            // html    : '<h1 class="x-panel-header"><div align=\'center\'><font size="3">' + FrontSuite.options['app.title'] + '</div></h1>',
            bbar: [
               {
                   xtype: 'label',
                   text: FrontSuite.options['app.title'],
                   margins : '0 10 0 10',
                   style: {
                       'font-size': '18px',
                       'font-weight': 'bold'
                   }
               },
               '-',
               {
                   xtype: 'button',
                   text: 'View',
                   // handler: function(btn) {
                   //   alert('Button Click');
                   // }
                   menu: [
                       { text: 'Full Screen' },
                       '-',
                       { text: 'View 1' },
                       { text: 'View 2' },
                       { text: 'View 3' },
                       { text: 'View 4' }
                   ]
               },
               '->',
               {
                   text: 'Usage'
               },
               '-',
               {
                   text: 'Database',
                   // handler: function(btn) {
                   //   alert('Button Click');
                   // }
                   menu: [
                       { text: 'Select',
                         menu: [
                           { text: 'app'}
                         ]
                       },
                       { text: 'Connect',
                         tooltip: {
                           text: 'Define the connection parameters for a database that you know how to log in to. This will allow you to browse that database using this tool.'
                         },
                         handler: function(btn) {
                           alert('Connect to Database');
                         }
                       },
                       { text: 'Create',
                         tooltip: {
                           text: 'Create a new database using one of the enabled database storage engines. You will be able to extract data out of other viewable databases, put it in the new one, and perform local analysis on it.'
                         },
                         handler: function(){
                             var dialog = createFormModalDialog(createFormPanelFromTable('app','main','db'));
                             dialog.show();
                         }
                       },
                       { text: 'Refresh' },
                       { text: 'Backup',
                         tooltip: {
                           text: 'Backup the entire database to a file which can be downloaded.'
                         }
                       },
                       { text: 'Restore',
                         tooltip: {
                           text: 'Restore the entire database from a previously created backup file.'
                         }
                       },
                       { text: 'Drop',
                         tooltip: {
                           text: 'CAUTION!!! Drop (destroy, delete) the entire database.'
                         }
                       }
                   ]
               },
               {
                   text: 'Schema',
                   menu: [
                       { text: 'Select',
                         menu: [
                           { text: 'main'}
                         ]
                       },
                       { text: 'Create' },
                       { text: 'Refresh' },
                       { text: 'Backup' },
                       { text: 'Restore' },
                       { text: 'Drop' }
                   ]
               },
               {
                   text: 'Table',
                   menu: [
                       { text: 'Select',
                         menu: [
                           { text: 'db'},
                           { text: 'db_table_01'},
                           { text: 'db_table_02'},
                           { text: 'db_table_03'},
                           { text: 'db_table_04'},
                           { text: 'db_table_05'},
                           { text: 'db_table_06'},
                           { text: 'db_table_07'},
                           { text: 'db_table_08'},
                           { text: 'db_table_09'},
                           { text: 'db_table_10'},
                           { text: 'db_table_11'},
                           { text: 'db_table_12'},
                           { text: 'db_table_13'},
                           { text: 'db_table_14'},
                           { text: 'db_table_15'},
                           { text: 'db_table_16'},
                           { text: 'db_table_17'},
                           { text: 'db_table_18'},
                           { text: 'db_table_19'},
                           { text: 'db_table_20'}
                         ]
                       },
                       { text: 'Create' },
                       { text: 'Refresh' },
                       { text: 'Backup' },
                       { text: 'Restore' },
                       { text: 'Drop' }
                   ]
               },
               '-',
               {
                   text: 'Remote Sync',
                   // handler: function(btn) {
                   //   alert('Button Click');
                   // }
                   menu: [
                       { text: 'DBFoundry Account Setup' },
                       { text: 'DBFoundry Sync' }
                   ]
               },
               '-',
               { text: 'Bug Report/Suggestion' },
               { text: 'Help' }
            ],
            border  : false,
            margins : '0 0 5 0'
        }, {
            region      : 'west',
            id          : 'vp-region-nav',
            title       : 'Navigation',
            collapsible : true,
            width       : 250,
            split       : true,
            bodyStyle   : 'padding:2px;',
            layout : {
                type  : 'fit',
                align : 'stretch',
                pack  : 'start'
            },
            items       : [ navAccordion ]
        }, {
            region      : 'east',
            id          : 'vp-region-info',
            title       : 'Messages / Info',
            collapsible : true,
            collapsed   : false,
            split       : true,
            width       : 400,
            bodyStyle   : 'padding:2px',
            layout : {
                type  : 'fit',
                align : 'stretch',
                pack  : 'start'
            },
            items       : [ infoAccordion ]
        }, {
            region : 'center',
            xtype  : 'tabpanel',
            id     : 'vp-region-tabpanel'
        }]
    });
});

//region      : 'south',
//id          : 'vp-region-footer',
//title       : 'South Panel',
//collapsible : true,
//collapsed   : true,
//html        : 'Atlanta Falcons NOT - 2013 Super Bowl Champions! :(',
//split       : true,
//height      : 100,
//minHeight   : 100
